package com.gitee.wsl.serialization.id

import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlin.js.JsName
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic

/**
 * 一个使用字符串 [String] 作为ID值的 [ID] 实现。
 *
 * 任何 [ID] 类型都可以作为一个字符串类型进行序列化。如果希望通用化 [ID] ，无视它的具体类型而作为字符串进行序列化，
 * 参考序列化器 [AsStringIDSerializer]。
 *
 * @property value 字符串ID的源值
 */
@Serializable(with = StringID.Serializer::class)
public class StringID private constructor(public val value: String) : ID() {
    override fun toString(): String = value
    override fun hashCode(): Int = value.hashCode()

    override fun equals(other: Any?): Boolean {
        return idCommonEq(other) {
            if (it is StringID) return value == it.value

            value == it.toString()
        }
    }

    override fun equalsExact(other: Any?): Boolean {
        return idExactEq(other) {
            value == it.value
        }
    }

    override fun copy(): StringID = value.ID

    /**
     * 使 [StringID] 与某任意类型的 [ID] 排序。
     *
     * 如果目标类型是 [StringID] 或 [UUID]，则通过字面值排序。
     * 否则（是 [NumericalID]）始终得到 `-1`。
     *
     */
    override fun compareTo(other: ID): Int {
        if (other is StringID) {
            return value.compareTo(other.value)
        }

        return -1
    }

    public companion object {
        private val EMPTY = StringID("")

        /**
         * 通过 [String] 构建一个 [StringID].
         *
         */
        @get:JvmStatic
        @get:JvmName("valueOf")
        @get:JsName("valueOfString")
        public val String.ID: StringID get() = if (isEmpty()) EMPTY else StringID(this)

        /**
         * 通过 [CharSequence.toString] 构建一个 [StringID].
         *
         */
        @get:JvmStatic
        @get:JvmName("valueOf")
        @get:JsName("valueOfCharSequence")
        public val CharSequence.ID: StringID get() = if (isEmpty()) EMPTY else StringID(toString())
    }


    /**
     * 将ID视为字符串进行序列化/反序列化的序列化器。
     *
     * 会将任何 [ID] 序列化为 [String]；
     * 会将任何字符串反序列化为 [StringID]。
     *
     * 可以作为任意 [ID] 的通用序列化器。
     *
     */
    public object Serializer : KSerializer<StringID> {
        override fun deserialize(decoder: Decoder): StringID = decoder.decodeString().ID
        override val descriptor: SerialDescriptor =
            PrimitiveSerialDescriptor("StringID", PrimitiveKind.STRING)
        override fun serialize(encoder: Encoder, value: StringID) {
            encoder.encodeString(value.toString())
        }

    }
}